package com.lft.tree09.self_balanceing_bst;

// TreeOperation.java
public class TreeOperation {
    /*
    树的结构示例：
              1
            /   \
          2       3
         / \     / \
        4   5   6   7
    */
	
	// 用于获得树的层数
	public static int getTreeDepth(Node root) {
		return root == null ? 0 : (1 + Math.max(getTreeDepth(root.getLeft()), getTreeDepth(root.getRight())));
	}
	
	/**
	 * 将当前节点的
	 * @param currNode    当前节点
	 * @param rowIndex    行索引
	 * @param columnIndex 列索引
	 * @param res         存储数据的二维数组
	 * @param treeDepth   树的深度
	 */
	private static void writeArray(Node currNode, int rowIndex, int columnIndex, String[][] res, int treeDepth) {
		// 保证输入的树不为空
		if (currNode == null) {
			return;
		}
		// 先将当前节点的值保存到二维数组中
		res[rowIndex][columnIndex] = String.valueOf(currNode.getValue());
		
		// 计算当前位于树的第几层
		int currLevel = ((rowIndex + 1) / 2);
		
		// 若到了最后一层，则返回
		if (currLevel == treeDepth) {
			return;
		}
		
		// 计算当前行到下一行，每个元素之间的间隔（下一行的列索引与当前元素的列索引之间的间隔）
		int gap = treeDepth - currLevel - 1;
		
		// 对左儿子进行判断，若有左儿子，则记录相应的"/"与左儿子的值
		if (currNode.getLeft() != null) {
			res[rowIndex + 1][columnIndex - gap] = "/";
			writeArray(currNode.getLeft(), rowIndex + 2, columnIndex - gap * 2, res, treeDepth);
		}
		
		// 对右儿子进行判断，若有右儿子，则记录相应的"\"与右儿子的值
		if (currNode.getRight() != null) {
			res[rowIndex + 1][columnIndex + gap] = "\\";
			writeArray(currNode.getRight(), rowIndex + 2, columnIndex + gap * 2, res, treeDepth);
		}
	}
	
	/**
	 * 打印显示树
	 * @param root 传入根节点
	 */
	public static void show(Node root) {
		if (root == null) {
			System.out.println("EMPTY!");
		}
		// 得到树的深度
		int treeDepth = getTreeDepth(root);
		
		// 作为整个二维数组的宽度
		int arrayWidth = treeDepth * 2 - 1;
		
		// 最后一行的高度为2的（n - 1）次方乘3，再加1
		int arrayHeight = (2 << (treeDepth - 2)) * 3 + 1;
		// 用一个字符串数组来存储每个位置应显示的元素
		String[][] res = new String[arrayWidth][arrayHeight];
		// 对数组进行初始化，默认为一个空格
		for (int i = 0; i < arrayWidth; i++) {
			for (int j = 0; j < arrayHeight; j++) {
				res[i][j] = " ";
			}
		}
		
		// 从根节点开始，递归处理整个树
		writeArray(root, 0, arrayHeight / 2, res, treeDepth);
		
		// 此时，已经将所有需要显示的元素储存到了二维数组中，将其拼接并打印即可
		for (String[] row : res) {
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < row.length; i++) {
				sb.append(row[i]);
				if (row[i].length() > 1 && i <= row.length - 1) {
					i += row[i].length() > 4 ? 2 : row[i].length() - 1;
				}
			}
			System.out.println(sb.toString());
		}
	}
}